#! /usr/bin/env python
#-*- coding: utf-8 -*-

# Balloon - An alternative to DropBox with file version control.
# It is based on Mercurial and supports Git.
# Copyright (C) 2011  Cédric Bonhomme - http://cedricbonhomme.org/
#
# For more information : http://bitbucket.org/cedricbonhomme/balloon/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

__author__ = "Cedric Bonhomme"
__version__ = "$Revision: 0.1 $"
__date__ = "$Date: 2011/10/03 $"
__revision__ = "$Date: 2011/10/09 $"
__copyright__ = "Copyright (c) Cedric Bonhomme"
__license__ = "GPLv3"

import os
import pyinotify
import threading
import ConfigParser

import hgsync


# files to exclude from the monitoring
excl_file = os.path.join(os.getcwd(), 'exclude.lst')
excl = pyinotify.ExcludeFilter(excl_file)


# event triggered:
mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY | pyinotify.IN_MOVED_FROM | pyinotify.IN_MOVED_TO


class PTmp(pyinotify.ProcessEvent):
    """
    This class represent a watcher for the local repository.
    """
    def __init__(self, repository_name, type_repo, url, local_url, username):
        """
        """
        if type_repo == "hg":
            self.repo = hgsync.HgSync(repository_name, url, local_url, username)
            #self.repo.clone()
            self.in_from = ""

    def process_IN_CREATE(self, event):
        """
        Called when a file has been created.
        """
        if "hg-check" not in event.name:
            print "Created: %s " % os.path.join(event.path, event.name)
            self.repo.add(os.path.join(event.path, event.name))

    def process_IN_DELETE(self, event):
        """
        Called when a file has been deleted.
        """
        if "hg-check" not in event.name:
            print "Deleted: %s " % os.path.join(event.path, event.name)
            self.repo.remove(os.path.join(event.path, event.name))

    def process_IN_MODIFY(self, event):
        """
        Called when a file has been modified.
        """
        if "hg-check" not in event.name:
            print "Modified: %s " % os.path.join(event.path, event.name)
            self.repo.modify(os.path.join(event.path, event.name))

    def process_IN_MOVED_FROM(self, event):
        """
        Called when a file has been moved from (source).
        """
        if "hg-check" not in event.name:
            print "Moved From: %s " % os.path.join(event.path, event.name)
            self.in_from = os.path.join(event.path, event.name)

    def process_IN_MOVED_TO(self, event):
        """
        Called when a file has been moved to (destination).
        """
        if "hg-check" not in event.name:
            print "Moved To: %s " % os.path.join(event.path, event.name)
            self.repo.rename(self.in_from, os.path.join(event.path, event.name))
            self.in_from = ""


def start_watcher(repository_name, type_repo, username, password, url, local_url):
    """
    Start a watcher. This function is called in a separate thread.
    """
    wm = pyinotify.WatchManager()
    notifier = pyinotify.Notifier(wm, PTmp(repository_name, type_repo, \
                                            "https://" + username + ":" + password + "@" + url, \
                                            local_url, username))
    wdd = wm.add_watch((local_url) , mask, rec=True, auto_add=True, exclude_filter=excl)
    while True:
        try:
            notifier.process_events()
            if notifier.check_events():
                notifier.read_events()
        except KeyboardInterrupt:
            notifier.stop()
            break


if __name__ == "__main__":
    # Point of entry in execution mode.
    # load the configuration
    config = ConfigParser.SafeConfigParser()
    try:
        config.read("./balloon.cfg")
    except:
        pass

    for repository in config.sections():
        repository_name = config.get(repository, 'name')
        type_repo = config.get(repository, 'type')
        local_url = config.get(repository, 'local_url')
        url = config.get(repository, 'url')
        username = config.get(repository, 'username')
        password = config.get(repository, 'password')

        # Launch a new thread for the repository to watch
        thread = threading.Thread(None, start_watcher, None, (repository_name, type_repo, username, password, url, local_url))
        #thread.setDaemon(True)
        thread.start()